package cn.shop.merchant.service;

import cn.hutool.core.util.NumberUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import cn.shop.merchant.req.OrderQueryReq;
import cn.shop.merchant.service.message.MessageUtil;
import cn.shop.msgs.OrderMsg;
import cn.shop.transcation.merchantRateModule.entity.MerchantRate;
import cn.shop.transcation.merchantRateModule.mapper.MerchantRateMapper;
import cn.shop.transcation.merchantUser.mapper.entity.MerchantUser;
import cn.shop.transcation.order.entity.Order;
import cn.shop.transcation.order.entity.OrderRate;
import cn.shop.transcation.order.mapper.OrderMapper;
import cn.shop.utils.PageUtil;
import cn.shop.utils.Putif;
import cn.shop.utils.enums.OrderStatus;
import cn.shop.utils.exception.ServiceException;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.metadata.OrderItem;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * @author : 李一涵
 * @date : Created in 2021-11-8 14:08
 * @description : 订单service
 */
@Service
public class OrderService extends BaseServiceImpl<OrderMapper, Order> {

    private final static Logger LOG = LoggerFactory.getLogger(OrderService.class);

    @Resource
    private MerchantUserService userService;
    @Resource
    private MessageUtil messageUtil;
    @Resource
    private MerchantRateMapper rateMapper;
    @Resource
    private OrderRateService orderRateService;


    /**
     * 按条件查询订单列表
     *
     * @param req 查询条件
     * @param uid 商户编号
     */
    public Map<String, Object> orderList(OrderQueryReq req, long uid) {
        Page<Order> page = Page.<Order>of(req.getCurrent(), req.getSize());
        LambdaQueryWrapper<Order> query = Wrappers.<Order>lambdaQuery()
                .like(notBlank.test(req.getSellerName()), Order::getSellerName, req.getSellerName())
                .apply(notNull.test(req.getStatus()), "o.status = {0}", req.getStatus())
                .apply(notNull.test(req.getId()), "o.id = {0}", req.getId())
                .apply(notBlank.test(req.getPartitionName()), "mgp.name like {0}", "%" + filtration(req.getPartitionName()) + "%")
                .apply(notBlank.test(req.getAccount()), "fu.account = {0}", req.getAccount())
                .apply("o.uid = {0}", uid)
                .apply("o.deleted = {0}", false)
                .ge(notNull.test(req.getMin()), Order::getAmount, req.getMin())
                .le(notNull.test(req.getMax()), Order::getAmount, req.getMax());
        if (req.getStatus() == OrderStatus.COMPLETED) {
            page.addOrder(OrderItem.desc("o.deal_time"));
            query.apply(notNull.test(req.getStartTime()), req.gtTime("o.deal_time"), req.getStartTime())
                    .apply(notNull.test(req.getEndTime()), req.ltTime("o.deal_time"), req.getEndTime());
        } else {
            page.addOrder(OrderItem.desc("o.update_time"));
            query.apply(notNull.test(req.getStartTime()), req.gtTime("o.update_time"), req.getStartTime())
                    .apply(notNull.test(req.getEndTime()), req.ltTime("o.update_time"), req.getEndTime());
        }
        page = baseMapper.pageWithMerchantInfo(page, query);
        return PageUtil.formatPage(page, this::format);
    }

    public Map<String, Object> statistics(OrderQueryReq req, long uid) {
        LambdaQueryWrapper<Order> query = Wrappers.<Order>lambdaQuery()
                .like(notBlank.test(req.getSellerName()), Order::getSellerName, req.getSellerName())
                .apply(notNull.test(req.getStatus()), "o.status = {0}", req.getStatus())
                .apply(notNull.test(req.getId()), "o.id = {0}", req.getId())
                .apply(notBlank.test(req.getPartitionName()), "mgp.name like {0}", "%" + filtration(req.getPartitionName()) + "%")
                .apply(notBlank.test(req.getAccount()), "fu.account = {0}", req.getAccount())
                .apply("o.uid = {0}", uid)
                .apply("o.deleted = {0}", false)
                .ge(notNull.test(req.getMin()), Order::getAmount, req.getMin())
                .le(notNull.test(req.getMax()), Order::getAmount, req.getMax());
        if (req.getStatus() == OrderStatus.COMPLETED) {
            query.apply(notNull.test(req.getStartTime()), req.gtTime("o.deal_time"), req.getStartTime())
                    .apply(notNull.test(req.getEndTime()), req.ltTime("o.deal_time"), req.getEndTime());
        } else {
            query.apply(notNull.test(req.getStartTime()), req.gtTime("o.update_time"), req.getStartTime())
                    .apply(notNull.test(req.getEndTime()), req.ltTime("o.update_time"), req.getEndTime());
        }
        return baseMapper.statistics(query);
    }

    @Transactional(rollbackFor = Exception.class)
    public boolean audit(List<Long> ids, long uid, long operatorId) {
        MerchantUser user = userService.getById(uid);
        Order update = new Order();
        update.setStatus(OrderStatus.PASSED);
        update.setAuditId(operatorId);
        MerchantRate rate = rateMapper.selectById(uid);
        if (rate == null) {
            throw new ServiceException("未查到费率信息，请联系管理员");
        }
        if (rate.getRateType() || rate.getSingleType()) {
            BigDecimal charge = BigDecimal.ZERO;
            List<Order> orders = list(Wrappers.<Order>lambdaQuery().in(Order::getId, ids).eq(Order::getStatus, OrderStatus.AUDITING));
            if (rate.getRateType() ) { //金额手续费从商户扣
                //BigDecimal conversionUnit = NumberUtil.div(rate.getChargeRate().add(rate.getRateAdditional()), 100);
                BigDecimal conversionUnit = NumberUtil.div(rate.getChargeRate(), 100);
                BigDecimal amount = orders.stream().map(Order::getAmount).reduce(BigDecimal::add).orElse(BigDecimal.ZERO);
                charge = charge.add(NumberUtil.mul(amount, conversionUnit));
                LOG.info("金额手续费计算，比例：{}，总金额：{}，总手续费：{}", conversionUnit, amount, charge);
            }
            if (rate.getSingleType()) { //单笔手续费从商户扣
                charge = charge.add(ObjectUtil.defaultIfNull(rate.getChargeSingle(), BigDecimal.ZERO)
                        //.add(rate.getSingleAdditional())
                        .multiply(new BigDecimal(orders.size())));
                LOG.info("单笔手续费计算，单笔金额：{}，总笔数：{}，总手续费：{}", rate.getChargeSingle(), orders.size(), charge);
            }
            LOG.info("用户余额：{}，应扣收益：{}", user.getBalance(), charge);
            if (NumberUtil.isLess(user.getBalance(), charge)) {
                throw new ServiceException("账户余额小于" + charge.setScale(2, RoundingMode.HALF_UP).doubleValue() + "，请减少订单勾选或充值后再审核");
            }
            if (!NumberUtil.equals(charge, BigDecimal.ZERO)) {
                LambdaUpdateWrapper<MerchantUser> updateWrapper = Wrappers.lambdaUpdate();
                updateWrapper.setSql("balance = balance - " + charge).
                        eq(MerchantUser::getId, uid);
                boolean isSuccess = userService.update(updateWrapper);
                if (!isSuccess) {
                    throw new ServiceException("余额扣除失败，审核不成功");
                }
            }
        }
        List<OrderRate> rates = new ArrayList<>();
        for (Long id : ids) {
            OrderRate r = new OrderRate();
            r.setId(id);
            r.setChargeRate(rate.getChargeRate());
            r.setChargeSingle(rate.getChargeSingle());
            r.setRateAdditional(rate.getRateAdditional());
            r.setSingleAdditional(rate.getSingleAdditional());
            r.setRateType(rate.getRateType());
            r.setSingleType(rate.getSingleType());
            r.setCreateTime(LocalDateTime.now());
            rates.add(r);
        }
        orderRateService.saveBatch(rates);
        LocalDateTime now = LocalDateTime.now();
        update.setDownTime(now.plusDays(user.getPublicity()));
        update.setUpTime(now);
        boolean isSuccess = update(update, Wrappers.<Order>lambdaUpdate()
                .in(Order::getId, ids)
                .eq(Order::getUid, uid));
        if (!isSuccess) {
            throw new ServiceException("审核失败");
        }
        return true;
    }

    /**
     * 修改订单状态
     * @param ids 订单编号
     * @param uid 商户编号
     * @param operatorId 操作人
     * @param status 状态
     */
    @Transactional(rollbackFor = Exception.class)
    public boolean changeStatus(long[] ids, long uid, long operatorId, OrderStatus status) {
        MerchantUser user = userService.getById(uid);
        List<Long> idList = Arrays.stream(ids).boxed().collect(Collectors.toList());
        Order update = new Order();
        update.setStatus(status);
        update.setAuditId(operatorId);
        if (status == OrderStatus.PASSED) {
            update.setDownTime(LocalDateTime.now().plusDays(user.getPublicity()));
        }
        boolean isSuccess = update(update, Wrappers.<Order>lambdaUpdate()
                .in(Order::getId, idList)
                .eq(Order::getUid, uid));
        if (isSuccess) {
            if (status == OrderStatus.REJECTED) {
                try {
                    messageUtil.sendMessage(OrderMsg.TOPIC, OrderMsg.TAG, OrderMsg.start()
                                    .id(ids)
                                    .time(LocalDateTime.now())
                                    .status(status));
                } catch (Exception e) {
                    LOG.info("消息发送错误", e);
                }
            }
        }
        return isSuccess;
    }

    public BigDecimal sumAmount(Long pid, String nickname, String account, Long uid) {
        return baseMapper.sumAmount(pid, nickname, account, uid);
    }

    public Map<String, Object> statusCount(long uid) {
        long all = count(Wrappers.<Order>lambdaQuery()
                .eq(Order::getUid, uid));
        long auditing = count(Wrappers.<Order>lambdaQuery()
                .eq(Order::getUid, uid)
                .eq(Order::getStatus, OrderStatus.AUDITING));
        long completed = count(Wrappers.<Order>lambdaQuery()
                .eq(Order::getUid, uid)
                .eq(Order::getStatus, OrderStatus.COMPLETED));
        long selling = count(Wrappers.<Order>lambdaQuery()
                .eq(Order::getUid, uid)
                .eq(Order::getStatus, OrderStatus.PASSED));
        return Putif.start()
                .anyway("all", all)
                .anyway("auditing", auditing)
                .anyway("completed", completed)
                .anyway("selling", selling)
                .get();
    }

    /**
     * 格式化订单信息
     *
     * @param order 订单信息
     * @return 格式化以后的结果
     */
    private Map<String, Object> format(Order order) {
        List<String> accounts = StrUtil.split(order.getSellerAccount(), "э");
        return Putif.start()
                .anyway("id", order.getId())
                .anyway("partition", order.getPartitionName())
                .anyway("game", order.getGameName())
                .anyway("account", accounts.isEmpty() ? "" : accounts.get(0))
                .anyway("risk", order.getRisk())
                .anyway("seller", order.getSellerName())
                .anyway("amount", order.getAmount())
                .anyway("goods", order.getGoodsNum() > 1 ? order.getGoodsNum() + order.getGoods() : order.getGoods())
                .anyway("status", order.getStatus().description())
                .anyway("downTime", order.getDownTime())
                .anyway("createTime", order.getUpdateTime())
                .anyway("webAccount", order.getWebAccount())
                .get();
    }


    private String filtration(String str){
        if(StrUtil.isNotEmpty(str)) {
            String inj_str = "|select|and|or|like|regxp|from|where|update|exec|order|by|having|drop|delete|count|chr|mid|master|truncate|chardeclare|;||( )|[ ]|< >|,|.|;|'|\"|#|%|+|=|*|+|,";
            //这里的东西还可以自己添加
            String[] stra = inj_str.split("\\|");
            for (int i = 0; i <= stra.length-1; i++) {
                if (str.contains(stra[i])) {
                    //清除包含的值
                    String a = stra[i];
                    str = str.replace(a, "");
                }
            }
            return str;
        }else{
            return str;
        }
    }
}
